<!--
  - @copyright Copyright (c) 2019 Georg Ehrke <oc.list@georgehrke.com>
  -
  - @author Georg Ehrke <oc.list@georgehrke.com>
  -
  - @license GNU AGPL version 3 or any later version
  -
  - This program is free software: you can redistribute it and/or modify
  - it under the terms of the GNU Affero General Public License as
  - published by the Free Software Foundation, either version 3 of the
  - License, or (at your option) any later version.
  -
  - This program is distributed in the hope that it will be useful,
  - but WITHOUT ANY WARRANTY; without even the implied warranty of
  - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  - GNU Affero General Public License for more details.
  -
  - You should have received a copy of the GNU Affero General Public License
  - along with this program. If not, see <http://www.gnu.org/licenses/>.
  -
  -->

<template>
	<Multiselect
		class="invitees-search"
		:options="matches"
		:searchable="true"
		:internal-search="false"
		:max-height="600"
		:show-no-results="true"
		:show-no-options="false"
		:placeholder="placeholder"
		:class="{ 'showContent': inputGiven, 'icon-loading': isLoading }"
		open-direction="bottom"
		track-by="email"
		label="dropdownName"
		@search-change="findAttendees"
		@select="addAttendee">
		<!--<template slot="singleLabel" slot-scope="props"><img class="option__image" :src="props.option.img" alt="No Man’s Sky"><span class="option__desc"><span class="option__title">{{ props.option.title }}</span></span></template>-->
		<template slot="singleLabel" slot-scope="props">
			<div class="invitees-search-list-item">
				<Avatar v-if="props.option.isUser" :user="props.option.avatar" :display-name="props.option.dropdownName" />
				<Avatar v-if="!props.option.isUser" :url="props.option.avatar" :display-name="props.option.dropdownName" />
				<div v-if="props.option.hasMultipleEMails" class="invitees-search-list-item__label invitees-search-list-item__label--with-displayname">
					<div>
						{{ props.option.commonName }}
					</div>
					<div>
						{{ props.option.email }}
					</div>
				</div>
				<div v-else class="invitees-search-list-item__label invitees-search-list-item__label--single-email">
					<div>
						{{ props.option.dropdownName }}
					</div>
				</div>
			</div>
		</template>
		<template slot="option" slot-scope="props">
			<div class="invitees-search-list-item">
				<Avatar v-if="props.option.isUser" :user="props.option.avatar" :display-name="props.option.dropdownName" />
				<Avatar v-if="!props.option.isUser" :url="props.option.avatar" :display-name="props.option.dropdownName" />
				<div v-if="props.option.hasMultipleEMails" class="invitees-search-list-item__label invitees-search-list-item__label--with-multiple-email">
					<div>
						{{ props.option.commonName }}
					</div>
					<div>
						{{ props.option.email }}
					</div>
				</div>
				<div v-else class="invitees-search-list-item__label invitees-search-list-item__label--single-email">
					<div>
						{{ props.option.dropdownName }}
					</div>
				</div>
			</div>
		</template>
	</Multiselect>
</template>

<script>
import Avatar from '@nextcloud/vue/dist/Components/Avatar'
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'
import { findPrincipalsByDisplayName } from '../../../services/caldavService.js'
import HttpClient from '@nextcloud/axios'
import debounce from 'debounce'
import { linkTo } from '@nextcloud/router'

export default {
	name: 'InviteesListSearch',
	components: {
		Avatar,
		Multiselect,
	},
	props: {
		alreadyInvitedEmails: {
			type: Array,
			required: true,
		},
	},
	data() {
		return {
			isLoading: false,
			inputGiven: false,
			matches: [],
		}
	},
	computed: {
		placeholder() {
			return this.$t('calendar', 'Search for e-mails, users, contacts, resources or rooms')
		},
		noResult() {
			return this.$t('calendar', 'No match found')
		},
	},
	methods: {
		findAttendees: debounce(async function(query) {
			this.isLoading = true
			const matches = []

			if (query.length > 0) {
				const promises = [
					this.findAttendeesFromContactsAPI(query),
					this.findAttendeesFromDAV(query),
				]

				const [contactsResults, davResults] = await Promise.all(promises)
				matches.push(...contactsResults)
				matches.push(...davResults)

				// Source of the Regex: https://stackoverflow.com/a/46181
				// eslint-disable-next-line
				const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
				if (emailRegex.test(query)) {
					const alreadyInList = matches.find((attendee) => attendee.email === query)
					if (!alreadyInList) {
						matches.unshift({
							calendarUserType: 'INDIVIDUAL',
							commonName: query,
							email: query,
							isUser: false,
							avatar: null,
							language: null,
							timezoneId: null,
							hasMultipleEMails: false,
							dropdownName: query,
						})
					}
				}

				this.isLoading = false
				this.inputGiven = true
			} else {
				this.inputGiven = false
				this.isLoading = false
			}

			this.matches = matches
		}, 500),
		addAttendee(selectedValue) {
			this.$emit('addAttendee', selectedValue)
		},
		async findAttendeesFromContactsAPI(query) {
			let response

			try {
				response = await HttpClient.post(linkTo('calendar', 'index.php') + '/v1/autocompletion/attendee', {
					search: query,
				})
			} catch (error) {
				console.debug(error)
				return []
			}

			const data = response.data
			return data.reduce((arr, result) => {
				const hasMultipleEMails = result.emails.length > 1

				result.emails.forEach((email) => {
					let name
					if (result.name && !hasMultipleEMails) {
						name = result.name
					} else if (result.name && hasMultipleEMails) {
						name = `${result.name} (${email})`
					} else {
						name = email
					}

					if (this.alreadyInvitedEmails.includes(email)) {
						return
					}

					arr.push({
						calendarUserType: 'INDIVIDUAL',
						commonName: result.name,
						email: email,
						isUser: false,
						avatar: result.photo,
						language: result.lang,
						timezoneId: result.tzid,
						hasMultipleEMails,
						dropdownName: name,
					})
				})

				return arr
			}, [])
		},
		async findAttendeesFromDAV(query) {
			let results
			try {
				results = await findPrincipalsByDisplayName(query)
			} catch (error) {
				console.debug(error)
				return []
			}

			return results.filter((principal) => {
				if (!principal.email) {
					return false
				}

				if (this.alreadyInvitedEmails.includes(principal.email)) {
					return
				}

				// We do not support GROUPS for now
				if (principal.calendarUserType === 'GROUP') {
					return false
				}

				return true
			}).map((principal) => {
				return {
					commonName: principal.displayname,
					calendarUserType: principal.calendarUserType,
					email: principal.email,
					lang: null,
					isUser: principal.calendarUserType === 'INDIVIDUAL',
					avatar: principal.userId,
					hasMultipleEMails: false,
					dropdownName: principal.displayname || principal.email,
				}
			})
		},
	},
}
</script>
